// Includes
#include <PA9.h>       // Include for PA_Lib
#include "defines.h"

// The graphics
#include "gfx/all_gfx.c"
#include "gfx/all_gfx.h"

// The sounds
// Include the sound (found in the data folder in .raw format - for saberoff.raw use saberoff.h)
#include "time_passes.h"

#include "Creature.h"
#include "Pen.h"
#include "LifeDrop.h"

#include <stdlib.h>
#include <stdio.h>
#include <vector>
#include <time.h>


// Function: main()
int main(int argc, char ** argv)
{
	PA_Init();    // Initializes PA_Lib
	PA_InitVBL(); // Initializes a standard VBL
	AS_Init(AS_MODE_16CH);  // Init the sound system

	std::vector<LifeDrop*> drops;
	std::vector<int> dropNrs;
	dropNrs.push_back(SPRITE_DROP_00);
	dropNrs.push_back(SPRITE_DROP_01);
	dropNrs.push_back(SPRITE_DROP_02);
	dropNrs.push_back(SPRITE_DROP_03);
	

	// INTRO
	
	// INSTRUCTIONS

	// ######### LOAD GRAPHICS ##########
	
	// Load logo screens
	PA_EasyBgLoad(UPPER_SCREEN, 0, bg_upper_screen);
	PA_EasyBgLoad(LOWER_SCREEN, 0, bg_lower_screen);
	while(1)
	{
		if(Stylus.Newpress)
		{
			break;
		}
		PA_WaitForVBL();
	}

	// Load instruction screens (How to hold DS and such)
	PA_EasyBgLoad(UPPER_SCREEN, 0, bg_lower_screen);
	PA_EasyBgLoad(LOWER_SCREEN, 0, bg_upper_screen);
	while(1)
	{
		if(Pad.Newpress.Up || Pad.Newpress.Down || Pad.Newpress.Left || Pad.Newpress.Right || Pad.Newpress.A || Pad.Newpress.B || Pad.Newpress.X || Pad.Newpress.Y )
		{
			break;
		}
		PA_WaitForVBL();
	}

	// Load splash screen or something
	PA_EasyBgLoad(UPPER_SCREEN, 0, bg_lower_screen);
	PA_EasyBgLoad(LOWER_SCREEN, 0, bg_upper_screen);

	int v = 0;
	while(1)
	{
		v++;
		if(v > 100)
		{
			break;
		}
		PA_WaitForVBL();
	}

	// Load final backgrounds
	PA_EasyBgLoad(UPPER_SCREEN, 0, bg_lower_screen);
	PA_EasyBgLoad(LOWER_SCREEN, 0, bg_upper_screen);
	
	// Load creature palette
	PA_LoadSpritePal(UPPER_SCREEN, // Screen
			CREATURE_PALETTE_NO, // Palette number
			(void*)creature_Pal);	// Palette name

	// Load pen palette on lower screen
	PA_LoadSpritePal(UPPER_SCREEN, // Screen
			PEN_PALETTE_NO, // Palette number
			(void*)pen_Pal);	// Palette name

	// Load pen palette on lower screen
	PA_LoadSpritePal(LOWER_SCREEN, // Screen
			PEN_PALETTE_NO, // Palette number
			(void*)pen_Pal);	// Palette name

	// Load interface palette on upper screen
	PA_LoadSpritePal(UPPER_SCREEN, // Screen
			INTERFACE_PALETTE_NO, // Palette number
			(void*)interface_Pal);	// Palette name



	// Load interface palette on lower screen	PA_LoadSpritePal(UPPER_SCREEN, // Screen			INTERFACE_PALETTE_NO, // Palette number			(void*)interface_Pal);	// Palette name	// Load creature sprite					
	PA_CreateSprite(UPPER_SCREEN, // Screen
			SPRITE_CREATURE_00, // Sprite number
			(void*)creature_static_00_Sprite, // Sprite name
			OBJ_SIZE_32X32, // Sprite size
			1, // 256 color mode
			CREATURE_PALETTE_NO, // Sprite palette number
			10, 50); // X and Y position on the screen


	// Load creature sprite					
	PA_CreateSprite(UPPER_SCREEN, SPRITE_CREATURE_01, (void*)creature_static_01_Sprite,
		OBJ_SIZE_32X32, 1, 	CREATURE_PALETTE_NO, 50, 10); // X and Y position on the screen

	// Load creature sprite					
	PA_CreateSprite(UPPER_SCREEN, SPRITE_CREATURE_02, (void*)creature_static_02_Sprite,
		OBJ_SIZE_32X32, 1, 	CREATURE_PALETTE_NO, 90, 10); // X and Y position on the screen

	// Load creature sprite					
	PA_CreateSprite(UPPER_SCREEN, SPRITE_CREATURE_03, (void*)creature_static_03_Sprite,
		OBJ_SIZE_32X32, 1, 	CREATURE_PALETTE_NO, 130, 10); // X and Y position on the screen


	// ## ENABLE ROTATION ON CREATURE SPRITES ##
	PA_SetSpriteRotEnable(UPPER_SCREEN, SPRITE_CREATURE_00,CREATURE_ROTSET);
	PA_SetSpriteRotEnable(UPPER_SCREEN, SPRITE_CREATURE_01,CREATURE_ROTSET);
	PA_SetSpriteRotEnable(UPPER_SCREEN, SPRITE_CREATURE_02,CREATURE_ROTSET);
	PA_SetSpriteRotEnable(UPPER_SCREEN, SPRITE_CREATURE_03,CREATURE_ROTSET);
	
	
	// Load pen sprites to lower screen
	PA_CreateSprite(LOWER_SCREEN, SPRITE_PEN_HIT, (void*)pen_touch_00_Sprite,
			OBJ_SIZE_32X32, 1, PEN_PALETTE_NO, 50, 50);
	PA_CreateSprite(LOWER_SCREEN, SPRITE_PEN_MISS, (void*)pen_touch_01_Sprite,
			OBJ_SIZE_32X32, 1, PEN_PALETTE_NO, 50, 50);	
	PA_CreateSprite(LOWER_SCREEN, SPRITE_PEN_ILLEGAL, (void*)pen_touch_02_Sprite,
			OBJ_SIZE_32X32, 1, PEN_PALETTE_NO, 50, 50);
	
	// Load pen sprites to upper screen
	PA_CreateSprite(UPPER_SCREEN, SPRITE_PEN_HIT, (void*)pen_touch_00_Sprite,
			OBJ_SIZE_32X32, 1, PEN_PALETTE_NO, 50, 50);
	PA_CreateSprite(UPPER_SCREEN, SPRITE_PEN_MISS, (void*)pen_touch_01_Sprite,
			OBJ_SIZE_32X32, 1, PEN_PALETTE_NO, 50, 50);	
	PA_CreateSprite(UPPER_SCREEN, SPRITE_PEN_ILLEGAL, (void*)pen_touch_02_Sprite,
			OBJ_SIZE_32X32, 1, PEN_PALETTE_NO, 50, 50);
	
			
	// Load game time gauge sprites on to the upper screen
	PA_CreateSprite(UPPER_SCREEN, SPRITE_GAUGE_GAME_TIME_00, (void*)gauge_game_time_Sprite,
			OBJ_SIZE_32X32, 1, INTERFACE_PALETTE_NO, 0, GAUGE_TIME_LEFT_HEIGHT);
	PA_CreateSprite(UPPER_SCREEN, SPRITE_GAUGE_GAME_TIME_01, (void*)gauge_game_time_Sprite,
			OBJ_SIZE_32X32, 1, INTERFACE_PALETTE_NO, 32, GAUGE_TIME_LEFT_HEIGHT);
	PA_CreateSprite(UPPER_SCREEN, SPRITE_GAUGE_GAME_TIME_02, (void*)gauge_game_time_Sprite,
			OBJ_SIZE_32X32, 1, INTERFACE_PALETTE_NO, 2*32, GAUGE_TIME_LEFT_HEIGHT);
	PA_CreateSprite(UPPER_SCREEN, SPRITE_GAUGE_GAME_TIME_03, (void*)gauge_game_time_Sprite,
			OBJ_SIZE_32X32, 1, INTERFACE_PALETTE_NO, 3*32, GAUGE_TIME_LEFT_HEIGHT);
	PA_CreateSprite(UPPER_SCREEN, SPRITE_GAUGE_GAME_TIME_04, (void*)gauge_game_time_Sprite,
			OBJ_SIZE_32X32, 1, INTERFACE_PALETTE_NO, 4*32, GAUGE_TIME_LEFT_HEIGHT);
	PA_CreateSprite(UPPER_SCREEN, SPRITE_GAUGE_GAME_TIME_05, (void*)gauge_game_time_Sprite,
			OBJ_SIZE_32X32, 1, INTERFACE_PALETTE_NO, 5*32, GAUGE_TIME_LEFT_HEIGHT);
	PA_CreateSprite(UPPER_SCREEN, SPRITE_GAUGE_GAME_TIME_06, (void*)gauge_game_time_Sprite,
			OBJ_SIZE_32X32, 1, INTERFACE_PALETTE_NO, 6*32, GAUGE_TIME_LEFT_HEIGHT);
	PA_CreateSprite(UPPER_SCREEN, SPRITE_GAUGE_GAME_TIME_07, (void*)gauge_game_time_Sprite,
			OBJ_SIZE_32X32, 1, INTERFACE_PALETTE_NO, 7*32, GAUGE_TIME_LEFT_HEIGHT);
			
	// Load drop sprites on upper screen
	for (int i = SPRITE_DROP_00; i <= SPRITE_DROP_09 ; i++)
	{
		PA_CreateSprite(UPPER_SCREEN, i, (void*)life_drop_Sprite,
						OBJ_SIZE_32X32, 1, PEN_PALETTE_NO, 0, 0);
	}


	// ######### END LOADING OF GRAPHICS #########

	// Instantiate a creature
	Creature * theCreature = new Creature();
	
	// Instantiate a pen
	Pen * thePen = new Pen();
	
	// The number of frames (time) until the game ends
	int m_iGameTimeLeft = GAME_LENGTH; 
	
	// Infinite loop to keep the program running
	while (1)
	{
		// IS TILTED?
		
		// UPDATE TIME GAUGE
		// Loop through time gauge parts and update
		for (int i = SPRITE_GAUGE_GAME_TIME_00; i <= SPRITE_GAUGE_GAME_TIME_07; i++)
		{
			if (m_iGameTimeLeft < (i+1)*TIME_GAUGE_PART_TIME && PA_GetSpriteY(UPPER_SCREEN,i) < TIME_GAUGE_OFFSTAGE_Y)
			{
				// Move piece of time gauge offstage
				PA_SetSpriteY(UPPER_SCREEN,i,TIME_GAUGE_OFFSTAGE_Y);
				// Play time passes sound
				PA_PlaySimpleSound(time_passes);
			};
		}
		
		
		// If the stylus hit the screen
		if (Stylus.Newpress)
		{
			// The pen is usable
			if (thePen->IsUsable())
			{
				// If the creature hit by this touch?
				if( theCreature->IsHit(Stylus.X, Stylus.Y) )
				{
					// Creature was hitted
					thePen->Press(Stylus.X, Stylus.Y, HIT);
					if(theCreature->LifeDown() <= 0)
					{
						// Creature is dead, pen wins, huray
					}
				}
				// The creature was missed
				else
				{
					// Creature was missed
					thePen->Press(Stylus.X, Stylus.Y, MISS);
					if( theCreature->GetMaxLives() - theCreature->GetLivesLeft() > drops.size() 
						&& Stylus.X+CREATURE_SPRITE_SIZE/2 > EDGE_LEFT && Stylus.X+CREATURE_SPRITE_SIZE/2 < EDGE_RIGHT
						&& Stylus.Y+CREATURE_SPRITE_SIZE/2 > EDGE_TOP && Stylus.Y+CREATURE_SPRITE_SIZE/2 < EDGE_BOTTOM)
					{
						if(dropNrs.size() == 0)
						{
							break;
						}
						int spriteNr = dropNrs.back();
						dropNrs.pop_back();
						drops.push_back(new LifeDrop(Stylus.X-CREATURE_SPRITE_SIZE/2, Stylus.Y-CREATURE_SPRITE_SIZE/2, theCreature, spriteNr)); //spriteNr
						PA_SetSpriteXY(UPPER_SCREEN, spriteNr, Stylus.X-CREATURE_SPRITE_SIZE/2, Stylus.Y-CREATURE_SPRITE_SIZE/2);
						PA_StartSpriteAnimEx(UPPER_SCREEN, spriteNr, 0, 3, 1, ANIM_UPDOWN, -1);
					}
				}
			}
			// The pen is unusable
			else
			{			
				// Touch was illegal
				thePen->Press(Stylus.X, Stylus.Y, ILLEGAL);
			};
		}; // End pen logic
		
		
		// IS CREATURE MOVING
		
		
		// TIME PASSES
		thePen->Tick();
		theCreature->Tick();

		// Update drops		
		for(unsigned int i = 0; i < drops.size(); i++)
		{
			if(drops[i]->isAlive())
			{
				drops[i]->Tick();
			}
			else
			{
				//Hide grafic
				PA_SetSpriteXY(UPPER_SCREEN, drops[i]->GetSpriteNr(), 0, 0);

				// Re-add to sprite nrs list
				dropNrs.push_back(drops[i]->GetSpriteNr());

				//Kill object
				//delete drops[i];
				drops.pop_back();
			}
		}

		// Less game time left
		if (m_iGameTimeLeft > 0)
		{ 
			m_iGameTimeLeft--;
		};

		PA_WaitForVBL();
	}
	
	return 0;
} // End of main()
